#![allow(non_snake_case)]
mod month_picker;
mod panel;
mod quarter_picker;
mod year_picker;

use crate::_binder::Binder;
use chrono::{Datelike, NaiveDate};
use icondata as i;
use leptos::{html, prelude::*};
use leptos_icons::*;
pub use month_picker::MonthPicker;
use panel::{Panel, PanelRef};
pub use quarter_picker::QuarterPicker;
use shq_common::prelude::Size;
use thaw_components::{Follower, FollowerPlacement};
use thaw_utils::{now_date, ArcOneCallback, BoxOneCallback, ComponentRef, Model, SignalWatch};
pub use year_picker::YearPicker;

use crate::{
    date_picker::panel::PanelVariant,
    input::{Input, InputSuffix},
    InputPrefix,
};

#[component]
pub fn DatePicker(
    #[prop(optional, into)] value: Model<Option<NaiveDate>>,
    #[prop(optional, into)] placeholder: MaybeProp<String>,
    #[prop(optional, into)] on_change: Option<BoxOneCallback<Option<String>>>,
    #[prop(optional, into)] size: MaybeProp<Size>,
    #[prop(optional)] input_prefix: Option<InputPrefix>,
    #[prop(optional)] input_suffix: Option<InputSuffix>,
    #[prop(default=true.into(), into)] border: MaybeProp<bool>,
    #[prop(optional, into)] disabled: MaybeProp<bool>,
    #[prop(optional)] inner_max_width: u32,
    #[prop(optional)] is_init_focus: bool,
) -> impl IntoView {
    let date_picker_ref = NodeRef::<html::Div>::new();
    let is_show_panel = RwSignal::new(false);
    let show_date_text: RwSignal<Option<String>> = RwSignal::new(None);
    let show_date_format = "%Y%m%d";
    let update_show_date_text = move || {
        value.with_untracked(move |date| {
            let text = date
                .as_ref()
                .map_or(None, |date| Some(date.format(show_date_format).to_string()));
            show_date_text.set(text);
        });
    };
    update_show_date_text();
    let panel_ref = ComponentRef::<PanelRef>::default();
    let panel_selected_date = RwSignal::new(None::<NaiveDate>);
    _ = panel_selected_date.watch(move |date| {
        let text = date
            .as_ref()
            .map_or(None, |date| Some(date.format(show_date_format).to_string()));
        show_date_text.set(text);
    });

    let on_input_blur = BoxOneCallback::new(move |_| {
        // if let Ok(date) =
        //     NaiveDate::parse_from_str(&show_date_text.get_untracked(), show_date_format)
        // {
        //     if value.get_untracked() != Some(date) {
        //         value.set(Some(date));
        //         update_show_date_text();
        //     }
        // } else {
        //     update_show_date_text();
        // }
    });

    let close_panel = ArcOneCallback::new(move |date: Option<NaiveDate>| {
        if date.is_none() {
            is_show_panel.set(false);
            return;
        }
        if let Some(panel_ref) = panel_ref.get_untracked() {
            let pv = panel_ref.variant.get();
            let date = if pv == PanelVariant::Date {
                date
            } else if pv == PanelVariant::Month {
                let year_month = date.map(|d| (d.year(), d.month()));
                let day = value.get().map(|d| d.day()).unwrap_or(1);
                Some(
                    year_month
                        .map(|(year, month)| NaiveDate::from_ymd_opt(year, month as u32, day))
                        .unwrap_or(Some(now_date())),
                )
                .flatten()
            } else {
                let year = date.map(|d| (d.year()));
                let (month, day) = value.get().map(|d| (d.month(), d.day())).unwrap_or((1, 1));
                Some(
                    year.map(|year| NaiveDate::from_ymd_opt(year, month as u32, day))
                        .unwrap_or(Some(now_date())),
                )
                .flatten()
            };
            if let Some(on_change) = on_change.as_ref() {
                on_change(date.map(|d| d.format(show_date_format).to_string()));
            }
            value.set(date);
            update_show_date_text();
            if pv == PanelVariant::Date {
                is_show_panel.set(false);
            } else if pv == PanelVariant::Month {
                panel_ref.init_panel(date.unwrap(), PanelVariant::Date);
            } else {
                panel_ref.init_panel(date.unwrap(), PanelVariant::Month);
            }
        } else {
            is_show_panel.set(false);
        }
    });

    let open_panel = BoxOneCallback::new(move |_| {
        panel_selected_date.set(value.get_untracked());
        if let Some(panel_ref) = panel_ref.get_untracked() {
            panel_ref.init_panel(
                value.get_untracked().unwrap_or(now_date()),
                PanelVariant::Date,
            );
        }
        is_show_panel.set(true);
    });
    view! {
        <Binder>
            <div node_ref=date_picker_ref>
                <Input value=show_date_text on_focus=open_panel on_blur=on_input_blur border size disabled placeholder input_prefix inner_max_width is_init_focus>
                    <InputSuffix slot>
                        <Icon icon=i::AiCalendarOutlined style="font-size: 18px"/>
                        {if let Some(suffix) = input_suffix.and_then(|suffix| suffix.if_.then_some(suffix)) {
                            view! { {(suffix.children)()} }.into()
                        } else {
                            None
                        }}
                    </InputSuffix>
                </Input>
            </div>
            <Follower slot show=is_show_panel placement=FollowerPlacement::BottomStart>
                <Panel
                    date_picker_ref
                    close_panel
                    selected_date=panel_selected_date
                    comp_ref=panel_ref
                    is_show_panel
                    selected_variant=PanelVariant::Date.into()
                />
            </Follower>
        </Binder>
    }
}
